/**
  ******************************************************************************
  * @file    flash.c
  * @author  测试1组（houtiezhu）
  * @version v0
  * @date    09-07-2019
  *
  * @verbatim
  **/
/* Includes ------------------------------------------------------------------*/

#include "define.h"
#include "disp.h"
#include "power.h"
#include "clk.h"
#include "gpio.h"
#include "time.h"
#include "uart.h"
#include "spk.h"
#include "flash.h"
#include "adc.h"
#include "algo.h"
#include "bp.h"
#include "func.h"
#include "op.h"
#include "pwm.h"
#include "SD93F115B_flash.h"
#include "string.h"



#define wb(addr, value)     (*((u8  volatile *) (addr)) = value)
#define rb(addr)            (*((u8  volatile *) (addr)))
#define whw(addr, value)    (*((u16 volatile *) (addr)) = value)
#define rhw(addr)           (*((u16 volatile *) (addr)))
#define ww(addr, value)     (*((u32 volatile *) (addr)) = value)
#define rw(addr)            (*((u32 volatile *) (addr)))

#define LIBCFG_FLASH_PAGESIZE             (512)
#define FLASH_PAGE_SIZE               (LIBCFG_FLASH_PAGESIZE)

uint8 	BPLevelType;
uint16   Det_DIA;
uint8   ResultDataS; 		 	//SYS
uint8   ResultDataD; 		 	//DIA
uint8   ResultDataH; 		 	//PUL
uint8   ResultDataDA;		 	//day
uint8   ResultDataHO;		 	//hour
uint8   ResultDataMI;		 	//min
uint16	RecentAddr;
uint16	NextAddr;
uint32	MemoryAddMark[16];		//标记已用位置

uint8 MemoryYear,MemoryMonth,MemoryDay,MemoryHour,MemoryMinute;
volatile union byte_bit	IDbuffer;

//=========================================================================================
u16 	MemoryEndIndex; //最后一笔起始地址
u16		MemoryFirstIndex;//最早一笔地址

u16   	MemoryIndex;	//记忆组数
u16		MemoryEndAdd;
u16		MemoryFirstAdd;

u16		MemoryCurrentIndex;//当前翻页笔数
u16		MemoryDispIndex;//当前显示数字，某些客户会反过来
u16		MemoryCurrentAdd;//当前地址
u16		MemoryPreAdd;//早一笔地址
u16		MemoryPostAdd;//后一笔地址
u16		MemorySet;
u8   	inbyte[16];
u8   	outbyte[16];
u32		Readbuf[4];
u32		Writebuf[4];

#define asize 8
#define acount 63//(512-8)/8

u32 MemBack[512/4];	//512字节一个扇区
//================================USER FLASH===============================================


//********************************
//读取AddrStart地址Length长度的数据,到pData数组
//********************************
uint8 FLASH_Read(u32 AddrStart,u32* pData,u32 Length)
{
  u32 Addr;

	if((AddrStart >= BootAddress && AddrStart <= CalAdd)||(AddrStart < UserStartAddress)||(AddrStart >= FlashEnd)) return FALSE; //限定范围

	if( ((AddrStart%4)!=0) || ((Length%4)!=0) )return FALSE;

	AddrStart /= 4;
	AddrStart *= 4;
	Length /= 4;
	Length *= 4;
	//FLASH_Unlock();
  for (Addr = AddrStart; Addr < AddrStart + Length; Addr += 4)
  {

		*pData  = rw(Addr);
		pData++;

  }
	//FLASH_Lock();
	return TRUE;
}



//********************************
//读取AddrStart地址一个字节数据
//********************************
uint8 FLASH_ReadAddr(u32 AddrStart)
{
	u8 AddrData;
	if((AddrStart >= BootAddress && AddrStart <= CalAdd)||(AddrStart < UserStartAddress)||(AddrStart >= FlashEnd)) return FALSE; //限定范围
	//FLASH_Unlock();
	AddrData = rb(AddrStart);
	//FLASH_Lock();
	return AddrData; //读一个字节

}



//********************************
//往AddrStart地址写入Length*4长度的数据,从pData数组
//********************************
uint8 FLASH_WrDataProgram(u32 AddrStart,u32* pData,u32 Length)
{
	u32 Addr;
	FLASH_Status FLASHState;

	if((AddrStart >= BootAddress && AddrStart <= CalAdd)||(AddrStart < UserStartAddress)||(AddrStart >= FlashEnd)) return FALSE;

	if( ((AddrStart%4)!=0) || ((Length%4)!=0) )return FALSE;

	AddrStart /= 4;
	AddrStart *= 4;
	Length /= 4;
	Length *= 4;
	//FLASH_Unlock();
  for (Addr = AddrStart; Addr < AddrStart + Length; Addr += 4)
  {
	FLASHState = FLASH_ProgramWord(Addr,*pData);
    if (FLASHState != FLASH_COMPLETE)
    {
      //err++;
		//FLASH_Lock();
		return FALSE;
    }
	else pData++;
  }
	//FLASH_Lock();
	return TRUE;
}

//********************************
//写入一个字节数据到AddrStart
//********************************
uint8 FLASH_WrByteDataProgram(u32 AddrStart,u8 pData)
{
	u32 Addr;
	FLASH_Status FLASHState;

	if((AddrStart >= BootAddress && AddrStart <= CalAdd)||(AddrStart < UserStartAddress)||(AddrStart >= FlashEnd)) return FALSE;
	//AddrStart /= 4;
	//AddrStart *= 4;
	Addr = AddrStart;
	//FLASH_Unlock();

	FLASHState = FLASH_ProgramByte(Addr,pData);
	if (FLASHState != FLASH_COMPLETE)
    {
      //err++;
		//FLASH_Lock();
		return FALSE;
    }
	else
	{
		//FLASH_Lock();
		return TRUE;
	}

}


//********************************
//擦除一个扇区512字节
//********************************
uint8 FLASH_PageErase(u32 AddrStart,u16 PageLength )
{
	u32 Addr;
	FLASH_Status  FLASHState;

	if((AddrStart >= BootAddress && AddrStart <= CalAdd)||(AddrStart < UserStartAddress)||(AddrStart >= FlashEnd)) return FALSE;
	AddrStart /= 512;
	AddrStart *= 512;
	//FLASH_Unlock();
  for (Addr = AddrStart; Addr < AddrStart + PageLength * FLASH_PAGE_SIZE;Addr += FLASH_PAGE_SIZE)// 页擦除
  {
    FLASHState = FLASH_ErasePage(Addr);//FLASH_ErasePage(uint32_t Page_Address)
    if (FLASHState != FLASH_COMPLETE)
    {
      //err++;
		//FLASH_Lock();
		return FALSE;
    }
  }
	//FLASH_Lock();
	return TRUE;
}
//============================================================================================================
//********************************
//检查某个扇区末尾8字节是否为0x0123456789abcdef
//********************************
u8  CheckSecData(u32 AddrStart)
{
	unsigned char flag=TRUE;
	uint32 KeyData[2];

	if((AddrStart >= BootAddress && AddrStart <= CalAdd)||(AddrStart < UserStartAddress)||(AddrStart >= FlashEnd)) return FALSE;
	if((AddrStart%512)!=0) flag=FALSE;

	FLASH_Read(AddrStart+504,KeyData,8);
	if(KeyData[0]!=0x01234567) flag=FALSE;
	if(KeyData[1]!=0x89abcdef) flag=FALSE;

	return  flag;
}

//*************************************
//读取一个扇区512字节,存在MemBack
//*************************************
u8 ReadSecData(u32 AddrStart)
{
	unsigned char flag=TRUE;
	if(CheckSecData(AddrStart)==TRUE)//1区完整
	{
		FLASH_Read(AddrStart,MemBack,512);
		if(CheckSecData(AddrStart+512)==FALSE)//2区出错
		{
			FLASH_PageErase(AddrStart+512,1);
			FLASH_WrDataProgram(AddrStart+512,MemBack,512);
		}
	}
	else//1区出错
	{
		if(CheckSecData(AddrStart+512)==TRUE)//2区完整
		{
			FLASH_Read(AddrStart+512,MemBack,512);
			FLASH_PageErase(AddrStart,1);
			FLASH_WrDataProgram(AddrStart,MemBack,512);
		}
		else//2区出错
		{
			flag=FALSE;
			if(MemoryMode) memset(MemBack,0xff,512);
		}
	}
	return flag;
}
//==================================================================================================
//==================================================================================================
//读8字节
void	readM24L16(void)
{
	uint8 flag;
	flag = TRUE;
	unsigned char j;
	uint16 temp;
	uint16 SecNum;
	outbyte[asize-1]=0;
	temp=EEPROMin;
	if(!UserA&&MemoryMode) temp+=UserBOffSet;

	if(temp>EEPROMinMax)
	{
		flag=FALSE;
	}
	else
	{
		SecNum=temp/acount;
		temp%=acount;
		temp*=asize;

		if(ReadSecData(UserStartAddress + (1024 * SecNum))==FALSE)
		{
			flag=FALSE;
		}
		else
		{
			FLASH_Read(UserStartAddress + (1024 * SecNum) + temp ,Readbuf,asize);
			for(j=0;j<asize;j+=4)
			{
					inbyte[j] = (u8)(Readbuf[j/4]>>24);
					inbyte[j+1] = (u8)(Readbuf[j/4]>>16);
					inbyte[j+2] = (u8)(Readbuf[j/4]>>8);
					inbyte[j+3] = (u8)(Readbuf[j/4]);
			}
			for(j=0;j<asize-1;j++)
			{
					outbyte[asize-1]+=inbyte[j];//校验
			}
			if(outbyte[asize-1]!=inbyte[asize-1])
			{
				flag=FALSE;
			}
			else flag=TRUE;
		}
	}

	if(flag==FALSE)
	{
		for(j=0;j<asize;j++)
		{
			inbyte[j]=0xff;
		}
		ReadEepromError=1;
	}
	else ReadEepromError=0;
}

//写8字节
void writeM24L16(void)
{
	unsigned char j;
	uint16 temp;
	uint16 SecNum;
	outbyte[asize-1]=0;
	temp=EEPROMin;
	if(!UserA&&MemoryMode) temp+=UserBOffSet;

	if(temp>EEPROMinMax)
	{

	}
	else
	{
		SecNum=temp/acount;
		temp%=acount;
		temp*=asize;

		ReadSecData(UserStartAddress + (1024 * SecNum));
		for(j=0;j<asize-1;j++)
		{
			outbyte[asize-1]+=outbyte[j];
		}
	    for(j=0;j<asize;j+=4)
			{
				Writebuf[j/4] = (u32)(outbyte[j]<<24 | outbyte[j+1]<<16 | outbyte[j+2]<<8 | outbyte[j+3]);
			}
			for(j=0;j<(asize/4);j++)//12byte
			{
				MemBack[temp/4 + j] = Writebuf[j];//32bit
			}
			MemBack[126]=0x01234567;
			MemBack[127]=0x89abcdef;
			FLASH_PageErase(UserStartAddress + (1024 * SecNum),1);//
			FLASH_WrDataProgram(UserStartAddress + (1024 * SecNum),MemBack,512);

			FLASH_PageErase(UserStartBak + (1024 * SecNum),1);//				//back memdata
			FLASH_WrDataProgram(UserStartBak + (1024 * SecNum),MemBack,512);
	}
}




//擦除两次
void   CLRMemoryBank(void)//设定Memory初始值
{
	MemoryMode=1;
	EEPROMin=0;
	readM24L16();

	memset(outbyte,0,sizeof(outbyte));
	outbyte[0]=0;
	outbyte[1]=1;
	outbyte[6]=0;//memoryfull

	EEPROMin=0;
	writeM24L16();//
	MemoryEndIndex = 1;
	MemoryFull = 0;
	MemoryMode=0;
}



//检查记忆
void   checkmemorybank(void)
{
	MemoryMode=1;
	EEPROMin=0;
	readM24L16();  //检验数据

	if (inbyte[6]==1)
	{
		MemoryFull = 1;
	}
	else
	{
		MemoryFull = 0;
	}
	MemoryEndIndex = inbyte[0];
	MemoryEndIndex<<=8;
	MemoryEndIndex += inbyte[1];

	if((MemoryEndIndex==0) || (inbyte[6]>1) || ReadEepromError || (MemoryEndIndex>(MemorySet+1)))
	{
		CLRMemoryBank();//重新设定索引区的值
	}
	MemoryMode=0;
}

void   checkmemorybankAB(void)
{
	MemoryMode=1;
	EEPROMin=0;
	readM24L16();
	if (inbyte[6]==1)
	{
		MemoryFull = 1;
	}
	else
	{
		MemoryFull = 0;
	}
	MemoryEndIndex = inbyte[0];
	MemoryEndIndex<<=8;
	MemoryEndIndex += inbyte[1];
	MemoryMode=0;
}
//================================================================================================
void savefunction(void)	//手动设定保存功能
{
	u8 j;

	outbyte[0]=BPLevelType<<4;
	outbyte[0]|=UartType;
 	outbyte[1]=KeyNumber<<4;
	outbyte[1]|=VoiceType;
	outbyte[2]=MemorySetType<<4;
	outbyte[2]|=VoiceType2;
	outbyte[3]=SystemSetFlag4.b;
	outbyte[4]=SystemSetFlag.b;
	outbyte[5]=SystemSetFlag2.b;
	outbyte[6]=SystemSetFlag3.b;
	outbyte[7]=outbyte[0]+outbyte[1]+outbyte[2]+outbyte[3]+outbyte[4]+outbyte[5]+outbyte[6];

	memset(MemBack,0xff,512);
	for(j=0;j<8;j+=4)
	{
		Writebuf[j/4] = (u32)(outbyte[j+3]<<24 | outbyte[j+2]<<16 | outbyte[j+1]<<8 | outbyte[j]);
	}
	for(j=0;j<2;j++)//12byte
	{
		MemBack[j] = Writebuf[j];//32bit
	}
	MemBack[126]=0x01234567;
	MemBack[127]=0x89abcdef;
	FLASH_PageErase(FunctionAdd,1);
	FLASH_WrDataProgram(FunctionAdd,MemBack,512);

	FLASH_PageErase(FunctionBak,1);
	FLASH_WrDataProgram(FunctionBak,MemBack,512);
}

void savecal(void)//保存校正值
{
	u8 j;
	outbyte[0]=0xaa;
	outbyte[1]=C11b;
	outbyte[2]=AA12b;
	outbyte[3]=B11b;
	outbyte[4]=AA11b;
	outbyte[5]=B12b;
	outbyte[6]=C12b;
	outbyte[7]=outbyte[0]+outbyte[1]+outbyte[2]+outbyte[3]+outbyte[4]+outbyte[5]+outbyte[6];
	memset(MemBack,0xff,512);
	for(j=0;j<8;j+=4)
	{
		Writebuf[j/4] = (u32)(outbyte[j]<<24 | outbyte[j+1]<<16 | outbyte[j+2]<<8 | outbyte[j+3]);
	}
	for(j=0;j<2;j++)//12byte
	{
		MemBack[j] = Writebuf[j];//32bit
	}
	MemBack[126]=0x01234567;
	MemBack[127]=0x89abcdef;
	FLASH_PageErase(CalAdd,1);
	FLASH_WrDataProgram(CalAdd,MemBack,512);

	FLASH_PageErase(CalBak,1);
	FLASH_WrDataProgram(CalBak,MemBack,512);
}



void   writeFULLmemorybank(void)
{
	uint16 	Temp_Det_DIA;
	MemoryMode=1;
	Minute=0;		/*  Minute Value */
	Hour=12;                /*  Hour Value */
	Day=1;                 	/*  Day Value */
	Month=1;               	/*  Month Value */
 	Year.b=20;
	delay(8);
 	CLRMemoryBank();
	Det_DIA=1;
	do
	{
	    MemoryMode=1;
	    if(Det_DIA <= 4)	//1~4
	    {
	    	if(Det_DIA==1)
	    	{
	    		ResultDataS = 180;
				ResultDataD = 100;
				ResultDataH = 80;
			}
			if(Det_DIA==2)
	    	{
	    		ResultDataS = 130;
				ResultDataD = 55;
				ResultDataH = 80;
			}
			if(Det_DIA==3)
	    	{
	    		ResultDataS = 120;
				ResultDataD = 80;
				ResultDataH = 80;
			}
			if(Det_DIA==4)
	    	{
	    		ResultDataS = 110;
				ResultDataD = 70;
				ResultDataH = 80;
			}
		}
		else if(Det_DIA <= 120)	//5 ~120
		{
			ResultDataS = 200-Det_DIA;
			ResultDataD = 140-Det_DIA;
			ResultDataH = 40+Det_DIA;
		}
		else if(Det_DIA <= 320)	//121 ~ 320	(200 memories)
		{
			Temp_Det_DIA = Det_DIA - 120;
			ResultDataS = 55 + Temp_Det_DIA;
			ResultDataD = 25 + Temp_Det_DIA;
			ResultDataH = 30 + Temp_Det_DIA;
		}
		else 	// >320 	(max 500 ,about 500 -320 = 180 memories)
		{
			Temp_Det_DIA = Det_DIA - 320;
			ResultDataS = 75 + Temp_Det_DIA;
			ResultDataD = 25 + Temp_Det_DIA;
			ResultDataH = 40 + Temp_Det_DIA;
		}
		Day+=5;
		if (Day>25)
			{
	        	 Day=1;
	        	 Month++;
	        	 if (Month==13)
	        	 {
	        	 	 Month=1;
	        	 	 Year.b++;
	        	 }
	        }

		Hour=Det_DIA%24;
		Minute=Det_DIA%60;
		ResultDataDA = Day+(Month&0x03)*64;		//M0+data
		ResultDataHO = Hour+(Month&0x0c)*16;
		ResultDataMI = Minute;
//		lastmodeAV ^= 1;				//set average mode
		savetomemory();
		DisplayToSYSDIA(Det_DIA,2);
		DisplayToMemorySet(MemoryEndIndex);
		Det_DIA++;
        delay(1);//连续存储可能引起写flash卡死，增加延迟
	}while(Det_DIA<=MemorySet);


	MemoryMode=1;
  	EEPROMin=0;
    readM24L16();

  outbyte[0]=MemoryEndIndex/0x100;
	outbyte[1]=MemoryEndIndex%0x100;
	outbyte[2]=inbyte[2];
	outbyte[3]=inbyte[3];
	outbyte[4]=inbyte[4];
	outbyte[5]=inbyte[5];
	if (MemoryFull)	outbyte[6]=1;
	else outbyte[6]=0;

	EEPROMin=0;
	writeM24L16();

	MemoryMode=0;
}



void SaveSet(void)	//保存用户设定
{
				EEPROMin = UserSetAdd;
				if(mmHgkPaFlag==1){outbyte[0]=inbyte[0]|0x01;}
				else{outbyte[0]=inbyte[0]&0xfe;}

				if(VoiceEnable==1){outbyte[0]=outbyte[0]|0x02;}
				else{outbyte[0]=outbyte[0]&0xfd;}

				if(UserA==1){outbyte[0]=outbyte[0]|0x04;}
				else{outbyte[0]=outbyte[0]&0xfb;}

//				if(LastorSeven==1){outbyte[0]=outbyte[0]|0x08;}
//				else{outbyte[0]=outbyte[0]&0xf7;}

				outbyte[1]= ((e_voice_c_e_ma_switch & 0x0f) << 4) | VoiceLevel;
				outbyte[2]=inbyte[2];
				outbyte[3]=inbyte[3];
				outbyte[4]=inbyte[4];
				outbyte[5]=inbyte[5];
				outbyte[6]=inbyte[6];
				writeM24L16();
}

void checkeeprom(void)//优瑞恩用
{
	MemoryMode=1;
	checkmemorybankAB();
	DarkAllIcon();
	if(MemoryFull)						//Memory full
		{
			DisplayToMemorySet(MemorySet);
 		}
 	else								//Memory not full
     	{
  			DisplayToMemorySet(MemoryEndIndex-1);
      	}
	UserABDisplay();
	ShowVoice();
  delay(64);
	MemoryMode=0;
}

void LoadMemory(void)
{
	MemoryMode=1;
	checkmemorybankAB();
	MemoryMode=1;
	EEPROMin = 0;
	readM24L16();

	MemoryEndIndex = inbyte[0];
	MemoryEndIndex<<=8;
	MemoryEndIndex += inbyte[1];
	MemoryEndIndex--;

	if(MemoryFull)	{MemoryIndex = MemorySet;}
	else			{MemoryIndex = MemoryEndIndex;}

	if((MemoryEndIndex==0 && MemoryFull==0)||(ReadEepromError==1)||(MemoryEndIndex>MemorySet)) MemoryIndex=0;

	DisplayToMemorySet(MemoryIndex);
}
